#pragma once

#include <iostream>
#include <unistd.h>
#include <unordered_set>
#include <cstring>
#include "InetAddr.hpp"
#include "Log.hpp"

using namespace log_ns;
class Command
{
public:
    Command()
    {
        // 初始化命令白名单
        _safe_cmd.insert("ls");
        _safe_cmd.insert("pwd");
        _safe_cmd.insert("whoami");
        _safe_cmd.insert("touch"); // touch xx.txt
        _safe_cmd.insert("which"); // which ls

    }
    ~Command(){}

    bool SafeCheck(const std::string& cmd)
    {
        for (auto& safe : _safe_cmd)
        {
            if (strncmp(safe.c_str(), cmd.c_str(), safe.size()) == 0)
                return true;
        }
        return false;
    }

    std::string Excute(const std::string& cmd)
    {
        // 检查命令是否安全
        if (!SafeCheck(cmd)) return "unsafe command";

        // 命令安全，可以执行
        std::string ret;
        FILE* fp = popen(cmd.c_str(), "r");
        if (fp)
        {
            // 执行成功，读取结果
            char buffer[1024];
            while(fgets(buffer, sizeof(buffer), fp))
            {
                ret += buffer;
            }
            // 读取完毕
            return ret.empty() ? "sucess" : ret; // 部分命令执行成功不会有结果
        }
        // 执行失败
        return "execute error";
    }

    void HandlerCommand(int sockfd, InetAddr& addr)
    {
        while (1) // 长服务
        {
            // 读取数据
            char command[1024];
            int n = recv(sockfd, command, sizeof(command)-1, 0);
            if (n > 0)
            {
                // 读取成功
                command[n] = 0;
                LOG(INFO, "get a command from client: %s, command: %s\n", addr.AddrStr().c_str(), command);

                // 执行命令
                std::string ret = Excute(command);

                ::send(sockfd, ret.c_str(), ret.size(), 0);
            }
            else if (n == 0)
            {
                // 断开连接
                LOG(INFO, "cilent %s quit\n", addr.AddrStr().c_str());
                break;
            }
            else
            {
                LOG(ERROR, "read error\n");
                break;
            }
        }
    }
private:
    std::unordered_set<std::string> _safe_cmd;
};